#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "serverclientsocketproc.h"
#include "server-socket.h"
#include "cgproto.pb.h"
#include "base.pb.h"
#include <QDebug>
#include "sysserverclientsocket.h"

CNS_SYS_REGISTER(SysServerClientSocket)

CNS_INIT(ServerClientSocketProc)
CNS_REGISTER_CNS_COM_FACTORY2(ServerClientSocketProc, CnsComponent)
//CNS_REGISTER_CNS_COM_FACTORY(ServerClientSocketProc)
CNS_INIT_END

SysServerClientSocket::SysServerClientSocket()
{

}

int SysServerClientSocket::client_initialize(ServerClientSocketProcPtr client, ServerSocketProcPtr server)
{
//	memset(client, 0, sizeof(*client));

    client->server = reinterpret_cast<ServerSocketProc*>(server.data());

    uv_tcp_init(server->getLoop(), &client->socket);
    c_cns::ref(reinterpret_cast<void**>(&client->socket.data), client.data());

    return 0;
}

void SysServerClientSocket::client_destroy(struct ServerClientSocketProc* client)
{
}

void SysServerClientSocket::_on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
    ServerClientSocketProc* client;

    client = CAST_REF_TYPE_FROM_VOID(ServerClientSocketProc, handle->data);

    buf->base = client->server->getBaseProto().getBuf();
    buf->len = client->server->getBaseProto().getSize();
}

void SysServerClientSocket::_on_disconnect(uv_handle_t* handle)
{
    // TODO: This is a dummy example

    struct ServerClientSocketProc* client = reinterpret_cast<struct ServerClientSocketProc*>(handle->data);

    client_destroy(client);
    free(client);
}

void SysServerClientSocket::_on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{
    ServerClientSocketProc* client;

    client = CAST_REF_TYPE_FROM_VOID(ServerClientSocketProc, stream->data);

    if (nread == 0) {
        return;
    }
    ServerSocketProc* server = CAST_REF_TYPE_FROM_VOID(ServerSocketProc, client->server);
    if (nread < 0) {
        qDebug() << QString("The client %1 disconnected!").arg(client->addr);
        server->exec("_on_close", Q_ARG(ServerClientSocketProc*, client));
        return;
    }
    long long count = nread;
    char *package = buf->base;
    BaseProto &proto = server->getBaseProto();
    uint32_t handleSize;

    do{
        char *msgBuf = proto.addToReceiveBuf(handleSize, package, static_cast<uint32_t>(count));

        if(msgBuf){

            cgproto::Message msg;

            if(proto.decode(msgBuf, msg))
            {
                qDebug() << QString("Client %1 read: %2:%3").arg(client->addr).arg(msg.type()).arg(msg.body().c_str());
                const QMap<QVariant, QVariant>& dispatcher = client->property("dispatcher").value<QMap<QVariant, QVariant>>();
                CnsComponentPtr p = dispatcher[msg.type()].value<CnsComponentPtr>();
                p->exec("_on_read", Q_ARG(ServerClientSocketProc*, client), QStringList(), Q_ARG(cgproto::Message&, msg));
            }
        } else break;
        count -= handleSize;
        package += handleSize;
    } while(count > 0);
}

void SysServerClientSocket::client_read(ServerClientSocketProc* client)
{
    uv_read_start(reinterpret_cast<uv_stream_t*>(&client->socket), _on_alloc_buffer, _on_read);
}

void SysServerClientSocket::f__on_disconnect(ServerClientSocketProc* client)
{
    uv_close(reinterpret_cast<uv_handle_t*>(&client->socket), _on_disconnect);
}
